﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;

namespace Spelprojekt.Model
{
    public class Game
    {             
        private static float g_jumpSpeed = 9.0f;
        private static float g_moveSpeed = 4.0f;

        public float m_playedTime = 0.0f;        

        public Map m_map;
        public Player m_player = new Player();

        public List<Enemy> m_enemies = new List<Enemy>(); 

        public Enemy m_enemy;                       
        
        Controller.GameStates m_gameState = new Controller.GameStates();       

        public Game()
        {            
            m_player = new Player();            
            m_map = new Map(ref m_player);            
        }

        public Game(int a_level)
        {           
            if (a_level == 1)
            {
                //Spawn Enemies on Specific Level on a chosen position
                m_enemies.Add(m_enemy = new Enemy(new Vector2(10.0f, 14.99f), new Vector2(0.5f)));
                m_enemies.Add(m_enemy = new Enemy(new Vector2(20.0f, 14.99f), new Vector2(1)));
                m_enemies.Add(m_enemy = new Enemy(new Vector2(30.0f, 14.99f), new Vector2(1.5f)));

                //Spawn Player on chosen Position
                m_player = new Player(new Vector2(2.0f, 14.99f));
                m_map = new Map(a_level, ref m_player);
            }

            else if (a_level == 4)
            {
                m_player = new Player(new Vector2(10.50f, 13.99f));
                m_map = new Map(a_level, ref m_player);
            }

            else if (a_level == 2)
            {
                m_enemies.Add(m_enemy = new Enemy(new Vector2(10.0f, 14.99f), new Vector2(5)));
                m_enemies.Add(m_enemy = new Enemy(new Vector2(15.0f, 14.99f), new Vector2(10)));
                m_enemies.Add(m_enemy = new Enemy(new Vector2(20.0f, 14.99f), new Vector2(15)));
                m_enemies.Add(m_enemy = new Enemy(new Vector2(25.0f, 14.99f), new Vector2(20)));
                m_enemies.Add(m_enemy = new Enemy(new Vector2(30.0f, 14.99f), new Vector2(25)));
                m_enemies.Add(m_enemy = new Enemy(new Vector2(35.0f, 14.99f), new Vector2(30)));

                m_player = new Player(new Vector2(2.0f, 13.99f));
                m_map = new Map(a_level, ref m_player);
            }
            else
            {
                m_player = new Player(new Vector2(2.0f, 13.99f));
                m_map = new Map(a_level, ref m_player);
            }
        }

        public void Update(float a_elapsedTime)
        {
            m_playedTime += a_elapsedTime;

            HandlePlayer(a_elapsedTime);

            HandleEnemies(a_elapsedTime);
        }
       
        public Vector2 Collide(Vector2 a_oldPos, Vector2 a_newPos, Vector2 a_size,ref Vector2 a_velocity, ref bool a_outCollideGround)
        {            
            if (m_map.IsCollidingAt(a_newPos, a_size, Tile.TileType.Blocked))
            {

                //try X movement
                Vector2 xMove = new Vector2(a_newPos.X, a_oldPos.Y);
                if (m_map.IsCollidingAt(xMove, a_size, Tile.TileType.Blocked) == false)
                {
                    a_velocity.Y = 0.0f;
                    a_velocity.X *= 0.30f;// friction should be time-dependant
                    a_outCollideGround = true;
                    return xMove;
                }               

                //try Y movement
                Vector2 yMove = new Vector2(a_oldPos.X, a_newPos.Y);
                if (m_map.IsCollidingAt(yMove, a_size, Tile.TileType.Blocked) == false)
                {
                    a_velocity.X = 0.0f;
                    a_velocity.Y *= 0.90f; // friction should be time-dependant
                    a_outCollideGround = true;
                    return yMove;
                } 
                              
                return a_oldPos;
            }            

            return a_newPos;
        }

        public void HandleEnemies(float a_elapsedTime)
        {
            foreach (Enemy enemy in m_enemies)
            {
                enemy.m_speed.Y += 9.82f * a_elapsedTime;
                Vector2 enemyNewPos = enemy.m_position + enemy.m_speed * a_elapsedTime;

                enemy.m_collideGround = false;
                enemy.m_position = Collide(enemy.m_position, enemyNewPos, m_enemy.m_size, ref enemy.m_speed, ref enemy.m_collideGround);

                if (m_player.doCollideFromWrongDirection(enemy))
                {
                    m_player.m_isDead = true;
                }

                if (enemy.m_position.X > m_player.m_position.X)
                {
                    enemy.m_speed.X -= 100 * a_elapsedTime;
                }
                else
                {
                    enemy.m_speed.X += 100 * a_elapsedTime;
                }
            }
        }

        public void HandlePlayer(float a_elapsedTime)
        {
            if (m_player.State == Player.PlayerState.Air)
            {
                m_player.m_speed.Y += 9.82f * a_elapsedTime;
            }

            if (m_map.IsCollidingWithDeadlyBlock(m_player.m_position, m_player.m_radius - 0.5f))
            {
                m_player.State = Player.PlayerState.Dead;
            }

            Vector2 playerNewPos = m_player.m_position + m_player.m_speed * a_elapsedTime;

            m_player.m_collideGround = false;
            m_player.m_position = Collide(m_player.m_position, playerNewPos, m_player.m_size, ref m_player.m_speed, ref m_player.m_collideGround);            
        }

        public bool LevelIsCleared()
        {
            if (m_map.IsAtExit(m_player.m_position, m_player.m_size, Tile.TileType.Exit) == false)
            {
                return false;
            }
            
            return true;
        }        

        public bool IsPlayerDead()
        {
            if (m_player.State == Player.PlayerState.Dead == false)
            {
                return false;
            }
            
            return true;
        }                               

        public void DoLose()
        {
            m_player = new Player();
        }        

        internal void DoPlayerJump()
        {
            if (m_player.m_collideGround)
            {
                m_player.m_speed.Y = -g_jumpSpeed;
            }
        }

        internal void DoMoveLeft()
        {            
            m_player.m_speed.X = -g_moveSpeed;
        }

        internal void DoMoveRight()
        {
            m_player.m_speed.X = +g_moveSpeed;
        }        
    }
}
